#ifndef __RUNNER_HPP__
#define __RUNNER_HPP__

#include <string>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#include "../common/util.hpp"
#include "../common/asynclog.hpp"

namespace yx
{
    class Runner
    {
    public:
        Runner() = default;
        ~Runner() = default;

        // return:
        //      1. int>0表示代码没有跑完,出现异常
        //      2. int==0表示代码跑完
        //      3. int<0内部错误
        static int run(const std::string &file_name, int cpu_limit /*s*/, int mem_limit /*KB*/)
        {
            // 1. 通过file_name生成对应的 .exe .rin .rout .rerr 文件名称
            std::string exe = PathUtil::getExe(file_name);
            // std::string rin = PathUtil::getRunIn(file_name);
            // std::string rout = PathUtil::getRunOut(file_name);
            // std::string rerr = PathUtil::getRunErr(file_name);

            // 2. 打开三个文件
            int rin_fd = open(PathUtil::getRunIn(file_name).c_str(), O_CREAT | O_RDONLY);
            int rout_fd = open(PathUtil::getRunOut(file_name).c_str(), O_CREAT | O_WRONLY);
            int rerr_fd = open(PathUtil::getRunErr(file_name).c_str(), O_CREAT | O_WRONLY);
            if (rin_fd < 0 || rout_fd < 0 || rerr_fd < 0)
            {
                (WLOG()("运行时打开标准文件失败!!!"));
                return -1;
            }

            pid_t pid = fork();
            if (pid < 0)
            {
                close(rin_fd);
                close(rout_fd);
                close(rerr_fd);
                (ELOG()("运行时fork创建进程失败!!!"));
                return -2;
            }
            else if (0 == pid)
            {
                dup2(rin_fd, 0);
                dup2(rout_fd, 1);
                dup2(rerr_fd, 2);
                // 设置时间内存的限制
                ProcessUtil::setCpuMemLimit(cpu_limit,mem_limit);
                execl(exe.c_str(), exe.c_str(), nullptr);
                (ELOG()("运行时execl进程替换失败!!!"));
                // 发送SIGKILL表示程序没有跑完
                kill(getpid(), SIGKILL);
            }
            // else
            //{
            close(rin_fd);
            close(rout_fd);
            close(rerr_fd);

            int status = 0;
            waitpid(pid, &status, 0);
            (ILOG()("运行 \"{}\" 时,等待子进程成功 exitcode = {} , signo = {} !!!",
                    file_name,
                    WEXITSTATUS(status),
                    (status & 0x7f)));

            return status & 0x7f;
            //}
        }
    };
}

#endif // __RUNNER_HPP__